/*
 * Copyright (C) 2025 Tsingteng MicroSystem
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * @file ce_t3t.c
 * @brief 卡模拟T3T相关操作API
 */

#include "nci_feature.h"
#include "nci_core.h"
#include "ce_int.h"
#if IS_FEATURE_ON(NCI_FEATURE_CE_DH)
#include "nfa_ce.h"

/**
 * @brief T3T根据system_code查找监听信息的节点
 *
 * @param[in] list 监听列表
 * @param[in] system_code 要查找的节点的system_code
 *
 * @return 成功返回节点指针，失败返回NULL
 */
static tCE_NODE *ce_t3t_find_listen_info(tCE_LIST *list, uint16_t system_code) {
    tCE_NODE *current = list->head;

    while (current != NULL) {
        if (current->listen_t3t.system_code == system_code) {
            NFCLOG_D("Find listen info node, system code 0x%02X", system_code);
            return current;
        }
        current = current->next;
    }

    NFCLOG_D("Not find listen info node, system_code: 0x%02X", system_code);
    return NULL;
}

/**
 * @brief T3T根据system_code删除监听信息的节点
 *
 * @param[in] list 监听列表指针
 * @param[in] system_code 要删除的节点的system_code
 *
 * @return 成功返回true，失败返回false
 */
static bool ce_t3t_remove_listen_info(tCE_LIST *list, uint16_t system_code) {
    tCE_NODE *current = list->head;

    while (current != NULL) {
        if (current->listen_t3t.system_code == system_code) {
            return ce_list_delete_node(list, current);
        }
        current = current->next;
    }
    return false;
}

/**
 * @brief T3T设置监听参数
 *
 * @param[in] list 监听列表指针
 * @param[in] max 最大identifier支持数量
 *
 * @return 成功返回true，失败返回false
 */
static bool ce_t3t_set_listen_params(tCE_LIST *list, uint8_t max) {
    OSI_CHK_PARAM_INVALID(!list, return false);
    OSI_CHK_PARAM_INVALID(max == 0, return false);
    bool ret = true;
    tNCI_REG regs[18] = {0};
    uint8_t idx = 0;
    uint8_t *p_params = NULL;
    uint16_t mask = 0xFFFF;
    tCE_NODE *current = list->head;

    for ( ; current != NULL && idx < max; current = current->next) {
        if (NCI_CE_T3T == current->tech) {
            regs[idx].id = LF_T3T_IDENTIFIERS_1 + idx;
            regs[idx].len = LF_T3T_IDENTIFIERS_LEN;
            regs[idx].value = (uint8_t*)osi_calloc(NCI_MAX_SENSF_RES_LEN);
            p_params = regs[idx].value;
            if (!p_params) {
                NFCLOG_E("Alloc LF_T3T_IDENTIFIERS params failed");
                ret = false;
                goto err;
            }
            UINT16_TO_STREAM_BE(p_params, current->listen_t3t.system_code);
            ARRAY_TO_STREAM_BE(p_params, current->listen_t3t.nfcid2, NCI_NFCID2_LEN);
            ARRAY_TO_STREAM_BE(p_params, current->listen_t3t.pmm, NCI_PMM_LEN);
            mask &= ~((uint16_t)(1 << idx));
            idx++;
        }
    }

    if (idx >= max) {
        NFCLOG_E("Listen info exceed nfcc support max, max = %u", max);
    }

    regs[idx].id = LF_T3T_FLAGS;
    regs[idx].len = LF_T3T_FLAGS_LEN;
    regs[idx].value = (uint8_t*)osi_calloc(LF_T3T_FLAGS_LEN);
    p_params = regs[idx++].value;
    if (!p_params) {
        NFCLOG_E("Alloc LF_T3T_FLAGS params failed");
        goto err;
    }
    UINT16_TO_STREAM_LE(p_params, (~mask));

    regs[idx].id = LF_T3T_RD_ALLOWED;
    regs[idx].len = LF_T3T_RD_ALLOWED_LEN;
    regs[idx].value = (uint8_t*)osi_calloc(LF_T3T_RD_ALLOWED_LEN);
    if (!regs[idx].value) {
        NFCLOG_E("Alloc LF_T3T_RD_ALLOWED params failed");
        goto err;
    }
    *(regs[idx++].value) = 0x01;

    if (nci_core_set_config(regs, idx) != NCI_STATUS_OK) {
        NFCLOG_E("Set config failed");
        ret = false;
        goto err;
    }

err:
    for(uint8_t i = 0; i < idx; i++) {
        if (regs[i].value) {
            osi_free(regs[i].value);
        }
    }
    return ret;
}

/**
 * @brief 注册T3T监听
 *
 * @param[in] id 监听ID
 * @param[in] param 监听参数
 *
 * @return 成功返回NCI_STATUS_OK，失败返回相应的错误码
 */
static tNCI_STATUS ce_t3t_register_listen(tNCI_CE_LISTEN_ID *id, tNCI_CE_LISTEN_PARAM *param) {
    OSI_CHK_PARAM_INVALID(!id, return NCI_STATUS_EXT_INVALID_PARAM);
    OSI_CHK_PARAM_INVALID(!param, return NCI_STATUS_EXT_INVALID_PARAM);
    tNCI_CE_MANAGER *ce = ce_get_instance();
    OSI_CHK_PARAM_INVALID(!ce, return NCI_STATUS_EXT_INVALID_PARAM);
    OSI_CHK_PARAM_INVALID(!ce->listen_list, return NCI_STATUS_EXT_INVALID_PARAM);
    tNCI_STATUS ret;

    tCE_NODE *node = ce_t3t_find_listen_info(ce->listen_list, id->system_code);
    if (node == NULL) {
        node = ce_node_create();
        if (node == NULL) {
            NFCLOG_E("Create node failed");
            return NCI_STATUS_CE_LIST_NODE_FAILED;
        }
        node->tech = id->tech;
        node->listen_t3t.system_code = id->system_code;
        if (!osi_memcpy_s(node->listen_t3t.nfcid2, NCI_NFCID2_LEN, param->t3t.nfcid2, NCI_NFCID2_LEN)) {
            NFCLOG_E("Failed to copy NFCID2");
            ret = NCI_STATUS_EXT_COPY_FAILED;
            goto err;
        }
        if (!osi_memcpy_s(node->listen_t3t.pmm, NCI_PMM_LEN, param->t3t.pmm, NCI_PMM_LEN)) {
            NFCLOG_E("Failed to copy PMM");
            ret = NCI_STATUS_EXT_COPY_FAILED;
            goto err;
        }
        if (!ce_list_add_last(ce->listen_list, node)) {
            NFCLOG_E("Add node to list failed");
            ret = NCI_STATUS_CE_LIST_NODE_FAILED;
            goto err;
        }
    }

    if (!ce_t3t_set_listen_params(ce->listen_list, ce->t3t.identifier_max)) {
        NFCLOG_E("Update listen params failed");
        return NCI_STATUS_CE_SET_LISTEN_PARAMS_FAILED;
    }

    return NCI_STATUS_OK;
err:
    ce_node_destroy(node);
    return ret;
}

/**
 * @brief 注销T3T监听
 *
 * @param[in] id 监听ID
 *
 * @return 成功返回NCI_STATUS_OK，失败返回相应的错误码
 */
static tNCI_STATUS ce_t3t_unregister_listen(tNCI_CE_LISTEN_ID *id) {
    OSI_CHK_PARAM_INVALID(!id, return NCI_STATUS_EXT_INVALID_PARAM);
    tNCI_CE_MANAGER *ce = ce_get_instance();
    OSI_CHK_PARAM_INVALID(!ce, return NCI_STATUS_EXT_INVALID_PARAM);
    OSI_CHK_PARAM_INVALID(!ce->listen_list, return NCI_STATUS_EXT_INVALID_PARAM);

    if (!ce_t3t_remove_listen_info(ce->listen_list, id->system_code)) {
        NFCLOG_E("Remove listen params failed");
        return NCI_STATUS_CE_LIST_NODE_FAILED;
    }

    if (!ce_t3t_set_listen_params(ce->listen_list, ce->t3t.identifier_max)) {
        NFCLOG_E("Update listen params set failed");
        return NCI_STATUS_CE_SET_LISTEN_PARAMS_FAILED;
    }

    return NCI_STATUS_OK;
}

/**
 * @brief 初始化T3T时获取NFCC支持的最大T3T标识符索引。
 *
 * @return 成功返回NCI_STATUS_OK，失败返回错误码。
 */
static tNCI_STATUS ce_t3t_get_identifier_max() {
    tNCI_CE_MANAGER *ce = ce_get_instance();
    OSI_CHK_PARAM_INVALID(!ce, return NCI_STATUS_EXT_INVALID_PARAM);
    tNCI_REG_ID reg_id = LF_T3T_MAX;
    tNCI_REG reg = {
        .id = LF_T3T_MAX,
        .len = sizeof(uint8_t),
        .value = &ce->t3t.identifier_max
    };
    tNCI_STATUS ret = nci_core_get_config(&reg_id, 1, &reg);
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("Get config failed");
        return ret;
    }
    NFCLOG_D("identifier_max = %u", ce->t3t.identifier_max);
    return NCI_STATUS_OK;
}
#endif // IS_FEATURE_ON(NCI_FEATURE_CE_DH)

/**
 * @brief T3T数据接收处理函数
 *
 * @param[in] p_data  接收到的数据指针
 * @param[in,out] p_len 数据长度指针，输入为接收到的数据长度，输出为处理后的数据长度
 *
 * @return 成功返回NCI_STATUS_OK，失败返回相应的错误码
 */
static tNCI_STATUS ce_t3t_receive_handler(const uint8_t *p_data, uint16_t *p_len) {
    (void)p_data;
    /* 去除尾部的状态字节 */
    (*p_len)--;
    return NCI_STATUS_OK;
}

#if IS_FEATURE_ON(NCI_FEATURE_CE_DH)
/**
 * @brief 上报NFCC支持的最大T3T标识符索引。
 *
 * @param[out] max 返回支持的最大T3T标识符索引。
 *
 * @return 成功返回NCI_STATUS_OK，失败返回错误码。
 */
tNCI_STATUS nfa_ce_get_lf_t3t_max(int *max) {
    OSI_CHK_PARAM_INVALID(!max, return NCI_STATUS_EXT_INVALID_PARAM);
    tNCI_CE_MANAGER *ce = ce_get_instance();
    OSI_CHK_PARAM_INVALID(!ce, return NCI_STATUS_EXT_INVALID_PARAM);
    *max = (int)ce->t3t.identifier_max;
    NFCLOG_D("Get lf_t3t_max = %d", *max);
    return NCI_STATUS_OK;
}

/**
 * @brief 初始化T3T模块
 *
 * @return 成功返回NCI_STATUS_OK，失败返回相应的错误码
 */
tNCI_STATUS ce_t3t_init() {
    NFCLOG_I("Enter");
    tNCI_STATUS ret = ce_t3t_get_identifier_max();
    if (ret != NCI_STATUS_OK) {
        NFCLOG_E("Get identifier max failed");
        goto exit;
    }

    return NCI_STATUS_OK;
exit:
    NFCLOG_I("Exit, failed to init T3T, ret = %d", ret);
    return ret;
}
#endif // IS_FEATURE_ON(NCI_FEATURE_CE_DH)

tNCI_CE_ACTS g_ce_t3t_acts = {
#if IS_FEATURE_ON(NCI_FEATURE_CE_DH)
    .register_listen = ce_t3t_register_listen,
    .unregister_listen = ce_t3t_unregister_listen,
#endif // IS_FEATURE_ON(NCI_FEATURE_CE_DH)
    .receive_handler = ce_t3t_receive_handler,
};
